﻿using System;
using System.Collections.Generic;
using Xilium.CefGlue.Demo.Internals.JavascriptBinding;

namespace Xilium.CefGlue.Demo
{

    #region 声明委托回调

    /// <summary>
    /// 网页脚本与后台程序交互方法
    /// 提示一：V8HandlerDelegate要在namespace下面定义，不要写到class里去了
    /// 提示二：如果 returnValue = null; 则会导致网页前端出现错误：Cannot read property 'constructor' of undefined
    /// 提示三：还存在其他的可能，导致导致网页前端出现错误：Cannot read property 'constructor' of undefined
    /// </summary>
    /// <param name="name">名称</param>
    /// <param name="obj">对象</param>
    /// <param name="arguments">参数</param>
    /// <param name="returnValue">返回值</param>
    /// <param name="exception">返回异常信息</param>
    /// <returns></returns>
    public delegate void V8HandlerDelegate(string name, CefV8Value obj, CefV8Value[] arguments, out CefV8Value returnValue, out string exception);

    #endregion 声明委托回调

    /// <summary>
    /// 渲染进程处理程器示例
    /// </summary>
    internal class DemoRenderProcessHandler : CefRenderProcessHandler
    {
        #region 声明常量变量

        /// <summary>
        /// 绑定测试处理器A
        /// </summary>
        private LiveV8Handler live;

        /// <summary>
        /// 绑定测试处理器B
        /// </summary>
        private ExampleBv8Handler exampleB;

        /// <summary>
        /// 委托回调
        /// </summary>
        public V8HandlerDelegate CallBack { get; set; }

        #endregion 声明常量变量

        #region 事件

        //protected override bool OnBeforeNavigation(CefBrowser browser, CefFrame frame, CefRequest request, CefNavigationType navigationType, bool isRedirect)
        //{
        //    Console.WriteLine("OnBeforeNavigation: Request.Url={0} NavigationType={1} IsRedirect={2}",
        //        request.Url,
        //        navigationType,
        //        isRedirect
        //        );

        //    return false;
        //}

        protected override bool OnProcessMessageReceived(CefBrowser browser, CefProcessId sourceProcess, CefProcessMessage message)
        {
            Console.WriteLine("Render::OnProcessMessageReceived: SourceProcess={0}", sourceProcess);
            Console.WriteLine("Message Name={0} IsValid={1} IsReadOnly={2}", message.Name, message.IsValid, message.IsReadOnly);
            var arguments = message.Arguments;
            for (var i = 0; i < arguments.Count; i++)
            {
                var type = arguments.GetValueType(i);
                object value;
                switch (type)
                {
                    case CefValueType.Null: value = null; break;
                    case CefValueType.String: value = arguments.GetString(i); break;
                    case CefValueType.Int: value = arguments.GetInt(i); break;
                    case CefValueType.Double: value = arguments.GetDouble(i); break;
                    case CefValueType.Bool: value = arguments.GetBool(i); break;
                    default: value = null; break;
                }

                Console.WriteLine("  [{0}] ({1}) = {2}", i, type, value);
            }

            if (message.Name == "myMessage2") return true;

            var message2 = CefProcessMessage.Create("myMessage2");
            var success = browser.SendProcessMessage(CefProcessId.Renderer, message2);
            Console.WriteLine("Sending myMessage2 to renderer process = {0}", success);

            var message3 = CefProcessMessage.Create("myMessage3");
            var success2 = browser.SendProcessMessage(CefProcessId.Browser, message3);
            Console.WriteLine("Sending myMessage3 to browser process = {0}", success);

            return false;
        }

        protected override void OnContextCreated(CefBrowser browser, CefFrame frame, CefV8Context context)
        {
            foreach (KeyValuePair<string, object> kvp in CefRuntimeEx.GetObjects())
            {
                BindingHandler.Bind(kvp.Key, kvp.Value, context.GetGlobal()); //绑定方式一
                //BindingHandler.Bind(kvp.Key, kvp.Value, context.GetGlobal(), false); //绑定方式二
            }

            base.OnContextCreated(browser, frame, context);
        }

        protected override void OnWebKitInitialized()
        {
            #region 原生方式注册 ExampleA

            live = new LiveV8Handler();

            const string exampleAJavascriptCode = @"function live() {}
            if (!live) live = {};
            (function() {

                live.__defineGetter__('token',
                function() {
                    native function GetToken();
                    return GetToken();
                });

                live.__defineSetter__('token',
                function(arg0) {
                    native function SetToken(arg0);
                    SetToken(arg0);
                });

                live.__defineGetter__('roomId',
                function() {
                    native function GetRoomId();
                    return GetRoomId();
                });

                live.__defineSetter__('roomId',
                function(arg0) {
                    native function SetRoomId(arg0);
                    SetRoomId(arg0);
                });

                live.__defineGetter__('teacherUid',
                function() {
                    native function GetTeacherUid();
                    return GetTeacherUid();
                });

                live.__defineSetter__('teacherUid',
                function(arg0) {
                    native function SetTeacherUid(arg0);
                    SetTeacherUid(arg0);
                });


                live.myFunction = function() {
                    native function MyFunction();
                    return MyFunction();
                };

                live.callLive = function() {
                    native function CallLive();
                    return CallLive();
                };

                live.GetToken = function() {
                    native function GetToken();
                    return GetToken();
                };

                live.SetToken = function(arg0) {
                    native function SetToken(arg0);
                    SetToken(arg0);
                };

                live.GetRoomId = function() {
                    native function GetRoomId();
                    return GetRoomId();
                };

                live.SetRoomId = function(arg0) {
                    native function SetRoomId(arg0);
                    SetRoomId(arg0);
                };

                live.GetTeacherUid = function() {
                    native function GetTeacherUid();
                    return GetTeacherUid();
                };

                live.SetTeacherUid = function(arg0) {
                    native function SetTeacherUid(arg0);
                    SetTeacherUid(arg0);
                };
            })();";

            CefRuntime.RegisterExtension("liveExtensionName", exampleAJavascriptCode, live);

            #endregion 原生方式注册 ExampleA

            #region 回调方式注册 ExampleB

            exampleB = new ExampleBv8Handler { CallBack = CallBackMethod };

            const string exampleBJavascriptCode = @"function exampleB() {}
            if (!exampleB) exampleB = {};
            (function() {
                exampleB.__defineGetter__('myProperty',
                function() {
                    native function MyProperty();
                    return MyProperty();
                });
                exampleB.__defineGetter__('myReadOnlyProperty',
                function() {
                    native function MyReadOnlyProperty();
                    return MyReadOnlyProperty();
                });
                exampleB.__defineGetter__('myUnconvertibleProperty',
                function() {
                    native function MyUnconvertibleProperty();
                    return MyUnconvertibleProperty();
                });
                exampleB.repeat = function(str,n) {
                    native function Repeat(str,n);
                    return Repeat(str,n);
                };
                exampleB.echoVoid = function() {
                    native function EchoVoid();
                    EchoVoid();
                };
                exampleB.echoBoolean = function(arg0) {
                    native function EchoBoolean(arg0);
                    return EchoBoolean(arg0);
                };
                exampleB.echoNullableBoolean = function(arg0) {
                    native function EchoNullableBoolean(arg0);
                    return EchoNullableBoolean(arg0);
                };
                exampleB.echoSByte = function(arg0) {
                    native function EchoSByte(arg0);
                    return EchoSByte(arg0);
                };
                exampleB.echoNullableSByte = function(arg0) {
                    native function EchoNullableSByte(arg0);
                    return EchoNullableSByte(arg0);
                };
                exampleB.echoInt16 = function(arg0) {
                    native function EchoInt16(arg0);
                    return EchoInt16(arg0);
                };
                exampleB.echoNullableInt16 = function(arg0) {
                    native function EchoNullableInt16(arg0);
                    return EchoNullableInt16(arg0);
                };
                exampleB.echoInt32 = function(arg0) {
                    native function EchoInt32(arg0);
                    return EchoInt32(arg0);
                };
                exampleB.echoNullableInt32 = function(arg0) {
                    native function EchoNullableInt32(arg0);
                    return EchoNullableInt32(arg0);
                };
                exampleB.echoInt64 = function(arg0) {
                    native function EchoInt64(arg0);
                    return EchoInt64(arg0);
                };
                exampleB.echoNullableInt64 = function(arg0) {
                    native function EchoNullableInt64(arg0);
                    return EchoNullableInt64(arg0);
                };
                exampleB.echoByte = function(arg0) {
                    native function EchoByte(arg0);
                    return EchoByte(arg0);
                };
                exampleB.echoNullableByte = function(arg0) {
                    native function EchoNullableByte(arg0);
                    return EchoNullableByte(arg0);
                };
                exampleB.echoUInt16 = function(arg0) {
                    native function EchoUInt16(arg0);
                    return EchoUInt16(arg0);
                };
                exampleB.echoUInt32 = function(arg0) {
                    native function EchoUInt32(arg0);
                    return EchoUInt32(arg0);
                };
                exampleB.echoNullableUInt32 = function(arg0) {
                    native function EchoNullableUInt32(arg0);
                    return EchoNullableUInt32(arg0);
                };
                exampleB.echoUInt64 = function(arg0) {
                    native function EchoUInt64(arg0);
                    return EchoUInt64(arg0);
                };
                exampleB.echoNullableUInt64 = function(arg0) {
                    native function EchoNullableUInt64(arg0);
                    return EchoNullableUInt64(arg0);
                };
                exampleB.echoSingle = function(arg0) {
                    native function EchoSingle(arg0);
                    return EchoSingle(arg0);
                };
                exampleB.echoNullableSingle = function(arg0) {
                    native function EchoNullableSingle(arg0);
                    return EchoNullableSingle(arg0);
                };
                exampleB.echoDouble = function(arg0) {
                    native function EchoDouble(arg0);
                    return EchoDouble(arg0);
                };
                exampleB.echoNullableDouble = function(arg0) {
                    native function EchoNullableDouble(arg0);
                    return EchoNullableDouble(arg0);
                };
                exampleB.echoChar = function(arg0) {
                    native function EchoChar(arg0);
                    return EchoChar(arg0);
                };
                exampleB.echoNullableChar = function(arg0) {
                    native function EchoNullableChar(arg0);
                    return EchoNullableChar(arg0);
                };
                exampleB.echoDateTime = function(arg0) {
                    native function EchoDateTime(arg0);
                    return EchoDateTime(arg0);
                };
                exampleB.echoNullableDateTime = function(arg0) {
                    native function EchoNullableDateTime(arg0);
                    return EchoNullableDateTime(arg0);
                };
                exampleB.echoDecimal = function(arg0) {
                    native function EchoDecimal(arg0);
                    return EchoDecimal(arg0);
                };
                exampleB.echoNullableDecimal = function(arg0) {
                    native function EchoNullableDecimal(arg0);
                    return EchoNullableDecimal(arg0);
                };
                exampleB.echoString = function(arg0) {
                    native function EchoString(arg0);
                    return EchoString(arg0);
                };
                exampleB.lowercaseMethod = function(arg0) {
                    native function LowercaseMethod(arg0);
                    return LowercaseMethod(arg0);
                };
            })();";

            CefRuntime.RegisterExtension("exampleBExtensionName", exampleBJavascriptCode, exampleB);

            #endregion 回调方式注册 ExampleB

            #region 调用自己封装的JS类库

            CefRuntimeEx.RegisterJsObject("exampleObject", new ExampleObject());

            #endregion 调用自己封装的JS类库

            #region 历史操作

            ////使用方法一
            //var bindingHandler = new BindingHandler {CallBack = CallBackMethod};
            //string javascriptCode = CefRuntimeEx.GetJavascriptFull("exampleObject", new ExampleObject(), bindingHandler);
            //CefRuntime.RegisterExtension("exampleObject" + "ExtensionName", javascriptCode, bindingHandler);

            ////使用方法二
            //CefRuntimeEx.RegisterJsObjectEx("exampleObject", new ExampleObject());

            #endregion 历史操作

            base.OnWebKitInitialized();
        }

        #endregion 事件

        #region 方法

        /// <summary>
        /// 利用委托回调方法
        /// 注意：如果 returnValue = null; 则会导致网页前端出现错误：Cannot read property 'constructor' of undefined
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        /// <param name="arguments"></param>
        /// <param name="returnValue"></param>
        /// <param name="exception"></param>
        public void CallBackMethod(string name, CefV8Value obj, CefV8Value[] arguments, out CefV8Value returnValue, out string exception)
        {
            returnValue = CefV8Value.CreateString(string.Empty);
            returnValue = CefV8Value.CreateString("sdklsdjklsdkljsdkljsdklsdjklsddjfklsdjklfjsdklj");


            exception = null;
        }

        #endregion 方法
    }
}